"""
A rudimentary bird.

Aims:

    * Get the bird to animate a 'flapping' motion.
    * Make it not look like all the bloody birds flap in unision.

    * on a collision \w air the bird's accy is increased up or down.
    * need some fancy trickery to make this a temporary accel.
      perhap some time delayed update?
"""

import pygame
from pygame.locals import *
import data
import math

import constants as c
import air
import animation as anim
import sounds

class Bird(pygame.sprite.Sprite):
    def __init__(self, x, y, animgroup):
        '''initial position and initial velocity in x and y dir.
        initial acceleration is assumed to be 0'''
        pygame.sprite.Sprite.__init__(self)


        self.rect = self.img_up.get_rect()
        # set some transparency.
        transparent = self.img_up.get_at((0, 0))
        self.img_up.set_colorkey(transparent)

        transparent = self.img_down.get_at((0, 0))
        self.img_down.set_colorkey(transparent)

        # set the current and next image. This means we can only
        # have a two part flap (not say a series of 10.)
        self.image = self.img_up
        self.x, self.y = (x, y)
        self.rect.topleft = (self.x, self.y)
        self._nxt_image = self.img_down

        # set initial velocities.
        self.velx, self.vely = self.v[0]/1000.0, self.v[1]/1000.0
        self.vely_orig = self.vely
        
        self._updates = {'time': self._timeupdate}

        # keep a count of how many frames have passed.
        # for updating bird flaps.
        self._frames = 0

        self._animgroup = animgroup

    def update(self, kwargs):
        '''bird accepts an update each frame.
        after a certain number of frames, bird changes image.'''

        # check if the bird image needs to change.
        self._frames = (self._frames + 1) % c.BIRD_FLAPUPDATE
        if not self._frames:
            # if it is time for a new flap. use this dirty round
            # robin to change the images over.
            temp = self.image
            self.image = self._nxt_image
            self._nxt_image = temp

        # a register construct. I keep a map of all the functions
        # and update keywords in _updates. Then I run any of the
        # update functions for which a keyword was sent...
        #
        # example.. I called update: bird.update({'time': 0.1})
        # this would call the function registered in _updates
        # under 'time' and run it with 0.1 as the argument.
        for kw, value in kwargs.items():
            fn = self._updates.get(kw, self._default)
            fn(value)

    def kill(self):
        "override kill to create an animation."
        pos = self.rect.topleft
        pygame.sprite.Sprite.kill(self)
        death_anim = anim.Animation('bird_die.png', pos, 100)
        self._animgroup.add(death_anim)

    def _default(self, *args):
        ' a do nothing function. harmless'
        pass

    def _timeupdate(self, time):
        # calculate change in x position.
        self.x = self.x + time * self.velx
        
        # calculate change in y position, allowing for air resistance
        # proportional to velocity
        self.y = self.y + time * self.vely
        self.vely = self.vely - c.MU * (self.vely - self.vely_orig)

        # apply the change
        self.rect.topleft = (self.x, self.y)

    def collide(self, other):
        'bird has collided with another object. air or windfarm'
        if isinstance(other, air.Air):
            # collided with the air, elastic collision
            self.vely = self.vely + other.m*other.v/self.m
            sounds.play_sfx('bird_hit.wav')

class Seagull(Bird):
    def __init__(self, *args, **kws):
        self.m = 9.0
        self.v = -100, 0
        ld_img = data.load_image
        self.img_up = ld_img("bird_flap_up.png", None)[0]
        self.img_down = ld_img("bird_flap_down.png", None)[0]
        Bird.__init__(self, *args, **kws)


def make_birdclass(mass, velocity, colour, alpha):
    class GenericBird(Bird):
        def __init__(self, *args, **kws):
            self.m = mass
            self.v = velocity
            ld_img = data.load_image
            self.img_up = ld_img("bird_flap_up.png", None)[0]
            self.img_down, rect = ld_img("bird_flap_down.png", None)
            mask = self.img_up.copy()
            mask.fill(colour)
            mask.set_alpha(alpha)
            self.img_up.blit(mask, (0, 0))
            self.img_down.blit(mask, (0, 0))
            Bird.__init__(self, *args, **kws)
    return GenericBird

Eagle = make_birdclass(15.0, (-100, 0), (200, 170, 149), 200)
Parrot = make_birdclass(5.0, (-130, 0), (190, 10, 0), 200)
BlackSwan = make_birdclass(13.0, (-150, 0), (0, 0, 0), 100)
